package cn.lumora.strategy;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.lumora.controller.req.LoginRequest;
import cn.lumora.core.security.password.PasswordUtil;
import cn.lumora.core.security.rea.RSACipherUtil;
import cn.lumora.core.security.rea.RSAKeyStorageService;
import cn.lumora.core.security.token.TempTokenService;
import cn.lumora.core.validation.PhoneLoginGroup;
import cn.lumora.core.validation.UsernameLoginGroup;
import cn.lumora.factory.RegisterStrategyFactory;
import cn.lumora.pojo.Player;
import cn.lumora.service.PlayerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.validation.Validator;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

/**
 * @author 刘智超
 * 账号密码登录
 */
@Component("passwordLoginStrategy")
@Slf4j
@Validated(PhoneLoginGroup.class)
public class PasswordLoginStrategy implements LoginStrategy {

    private final Validator validator;

    private final PlayerService playerService;

    private final RegisterStrategyFactory registerStrategyFactory;

    // 注入安全相关服务
    private final RSAKeyStorageService rsaKeyStorageService;
    private final TempTokenService tempTokenService;


    public PasswordLoginStrategy(
            Validator validator, PlayerService playerService,
            RegisterStrategyFactory registerStrategyFactory,
            RSAKeyStorageService rsaKeyStorageService,
            TempTokenService tempTokenService) {
        this.validator = validator;

        this.playerService = playerService;
        this.registerStrategyFactory = registerStrategyFactory;
        this.rsaKeyStorageService = rsaKeyStorageService;
        this.tempTokenService = tempTokenService;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String login(LoginRequest request) {
        Set<ConstraintViolation<LoginRequest>> violations = validator.validate(request, UsernameLoginGroup.class);
        if (!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
        }
        // 1. 验证临时令牌
        String tempToken = request.getTempToken();
        String requestUsername = request.getUsername();
        String username = tempTokenService.validateAndGetUsername(tempToken);

        if (username == null) {
            throw new RuntimeException("无效或已过期的临时令牌");
        }

        // 确保令牌绑定的用户名与请求中的用户名一致
        if (!username.equals(request.getUsername())) {
            throw new RuntimeException("临时令牌与用户名不匹配");
        }

        // 2. 获取RSA私钥用于解密密码
        String privateKey = rsaKeyStorageService.getPrivateKey();
        if (privateKey == null) {
            throw new RuntimeException("RSA私钥不可用");
        }

        // 3. 使用私钥解密请求中的密码
        String decryptedPassword = null;
        try {
            decryptedPassword = RSACipherUtil.decryptWithPrivateKey(request.getPassword(), privateKey);
        } catch (Exception e) {
            log.error("解密密码失败:{}", e.getMessage());
            throw new RuntimeException(e.getMessage());
        }

        // 验证用户名是否已存在
        if (playerService.checkUsername(request.getUsername())) {
            // 查询用户信息
            Player player = playerService.getPlayerByUsername(request.getUsername());

            // 5. 验证密码是否正确
            if (player != null && PasswordUtil.checkPassword(decryptedPassword, player.getPassword())) {
                // 密码正确，登录用户并返回token
                StpUtil.login(player.getId());
                log.info("getLoginId：{}", StpUtil.getLoginId());
                log.info("isLogin：{}", StpUtil.isLogin());
                return StpUtil.getTokenInfo().getTokenValue();
            } else {
                // 密码错误
                throw new RuntimeException("密码错误");
            }
        } else {
            // 用户名不存在 开始注册 根据策略注册
            int registerType = request.getLoginType();
            RegisterStrategy strategy = registerStrategyFactory.getStrategy(registerType);
            String register = strategy.register(request);
            if (ObjectUtil.isNotEmpty(register)) {
                log.info("注册成功");
                // 登录 生成token
                StpUtil.login(register);
                return StpUtil.getTokenInfo().getTokenValue();
            }

        }
        return null;
    }
}
